/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = cups_core.c                                                    */
/*  NOTE      = DRDA协议解析                                                  */
/*  DATE      = 2015/03/18 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>

#include "frservice_comm.h"
#include "cups_core.h"
#include "cups_comm.h"
#include "cups_request.h"
#include "cups_response.h"
#include "config.h"

extern void *g_p_apm_context;

/*******************************************************************************
*  FUNC     :  初始化私有cups session
*  ARGS     :  p_st_session(cups私有session)
*  RTN      :  FR_SUCC       (normal)
*              FR_FAIL       (error)
*  NOTE     :  p_st_session必须不为NULL
*******************************************************************************/
static int __cups_init_private(L7_session *p_st_session)
{
    L7_fragment_cups *p_st_fragment = NULL;               /* 分片包相关数据 */
    L7session_cups_private *p_st_private_session = NULL;  /* cups私有session */

    /* 申请整个私有session结构的内存 */
    p_st_private_session = (L7session_cups_private *)frmalloc(sizeof(L7session_cups_private));
    if (p_st_private_session == NULL)
    {
        goto error;
    }
    memset(p_st_private_session, 0x00, sizeof(L7session_cups_private));

    /* 申请分片包信息结构内存 */
    p_st_fragment = (L7_fragment_cups *)frmalloc(sizeof(L7_fragment_cups));
    if (p_st_fragment == NULL)
    {
        goto error;
    }
    memset(p_st_fragment, 0x00, sizeof(L7_fragment_cups));

    /* 设置初始化结构 */
    p_st_private_session->p_st_fragment = p_st_fragment;
    p_st_session->p_session_private = p_st_private_session;
    return FR_SUCC;

error:
    cups_free((char **)(&p_st_private_session));
    cups_free((char **)(&p_st_fragment));
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  初始化私有cups session
*  ARGS     :  p_st_private(私有session数据)
*  RTN      :  FR_SUCC       (normal)
*              FR_FAIL       (error)
*  NOTE     :  p_st_private必须不是NULL
*******************************************************************************/
static void __cups_destroy_curr_info(L7session_cups_private *p_st_private)
{
    if (p_st_private->p_st_req)
    {
        cups_destroy_request(&p_st_private->p_st_req);
    }
    if (p_st_private->p_st_resp)
    {
        cups_destroy_response(&p_st_private->p_st_resp);
    }
    cups_init_fragment(p_st_private->p_st_fragment);

    return;
}

/*******************************************************************************
*  FUNC     :  取得完整的packet包
*  ARGS     :  p_st_conn(connection信息)
*           :  p_st_packet(数据包信息)
*           :  p_st_private(私有session数据)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_TODO      (More data)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
static int __cups_set_analysis_data(Conntrack *p_st_conn
                                     , Apm_packet *p_st_packet
                                     , L7session_cups_private *p_st_private)
{
    int i_ret = FR_SUCC;
    int i_req_resp = 0;
    unsigned int ui_packet_len = 0;
    unsigned int ui_len = p_st_packet->ui_payload_len;
    char *p_data = p_st_packet->p_payload;
    L7_fragment_cups *p_st_fragment = p_st_private->p_st_fragment;
    Frbyte_Packet *p_st_data = NULL;

    if (p_data == NULL || ui_len == 0 || ui_len == 4)
    {
        return APM_L7_ANALYZE_TODO;
    }

    /* 取得方向 */
    i_req_resp = frcap_get_cs_direction(p_st_conn, p_st_packet->src_ip
                                        , p_st_packet->src_port);
    /* 创建bytebuffer */
    if (p_st_fragment->p_st_data == NULL)
    {
        /* 做成bytebuffer */
        p_st_fragment->p_st_data = bytebuff_creat();
        if (p_st_fragment->p_st_data == NULL)
        {
            frdbg("create bytebuff failed\n");
            return APM_L7_ANALYZE_FAIL;
        }
        p_st_data = p_st_fragment->p_st_data;
        /* 设置第一个分片包时间 */
        p_st_fragment->st_start_timestamp = p_st_packet->st_timestamp;
        /* 设置最后一个分片包时间 */
        p_st_fragment->st_end_timestamp = p_st_packet->st_timestamp;

        i_ret = bytebuff_add(p_st_data, p_data, ui_len);
        if (i_ret != FR_SUCC)
        {
            frdbg("add data to bytebuff failed\n");
            return APM_L7_ANALYZE_FAIL;
        }

        /* 取得packet长度 */
        i_ret = cups_get_len(p_st_data, CUPS_LEN_LEN, &ui_packet_len);
        if (i_ret != FR_SUCC)
        {
            frdbg("get packet length\n");
            return APM_L7_ANALYZE_FAIL;
        }
        ui_packet_len += CUPS_LEN_LEN;
        /* 解析head */
        i_ret = cups_parse_head(p_st_data, p_st_fragment->arr_dest_id
                                , p_st_fragment->arr_src_id
                                , p_st_fragment->arr_trans_info
                                , p_st_fragment->arr_msg_type
                                , p_st_fragment->arr_map_bit
                                , &p_st_fragment->ui_map_len
                                , &p_st_fragment->ui_rej_code);
        if (i_ret != FR_SUCC)
        {
            frdbg("parse head failed\n");
            return APM_L7_ANALYZE_FAIL;
        }
        frrtrim(p_st_fragment->arr_dest_id);
        frrtrim(p_st_fragment->arr_src_id);
        frrtrim(p_st_fragment->arr_trans_info);

        if (ui_packet_len < ui_len)
        {
            frdbg("length incorrect\n");
            return APM_L7_ANALYZE_FAIL;
        }
        else if (ui_packet_len == ui_len)
        {
            p_st_fragment->i_req_resp = i_req_resp;
            p_st_fragment->ui_packet_len = ui_packet_len;
            return APM_L7_ANALYZE_SUCC;
        }
        else
        {
            p_st_fragment->i_req_resp = i_req_resp;
            p_st_fragment->ui_packet_len = ui_packet_len;
            return APM_L7_ANALYZE_TODO;
        }
    }
    else
    {
        /* 前后两次方向不一致, 消除上次信息 */
        if (p_st_fragment->i_req_resp != i_req_resp)
        {
            cups_init_fragment(p_st_fragment);
            i_ret = __cups_set_analysis_data(p_st_conn, p_st_packet, p_st_private);
            return i_ret;
        }
        else
        {
            if (p_st_fragment->ui_packet_len < bytebuff_length(p_st_fragment->p_st_data) + ui_len)
            {
                cups_init_fragment(p_st_fragment);
                i_ret = __cups_set_analysis_data(p_st_conn, p_st_packet, p_st_private);
                return i_ret;
            }
            else if (p_st_fragment->ui_packet_len == bytebuff_length(p_st_fragment->p_st_data) + ui_len)
            {
                i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, ui_len);
                if (i_ret != FR_SUCC)
                {
                    frdbg("add data to bytebuff failed\n");
                    return APM_L7_ANALYZE_FAIL;
                }
                return APM_L7_ANALYZE_SUCC;
            }
            else
            {
                i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, ui_len);
                if (i_ret != FR_SUCC)
                {
                    frdbg("add data to bytebuff failed\n");
                    return APM_L7_ANALYZE_FAIL;
                }
                return APM_L7_ANALYZE_TODO;
            }
        }
    }
}

/*******************************************************************************
*  FUNC     :  判断当前数据链路是否是cups协议
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_packet(入力数据包)
*  RTN      :  APM_L7_IS_NO   (NO)
*              APM_L7_IS_YES  (YES)
*  NOTE     :
*******************************************************************************/
int cups_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    int i_ret = FR_SUCC;
    uint8_t u8_tpdu_len = 0;
    unsigned int ui_msg_type = 0;
    unsigned int ui_len = 0;
    unsigned int ui_packet_len = 0;
    char *p_data = NULL;
    Frbyte_Packet *p_st_data = NULL;

    //入力参数检查
    if(p_st_packet == NULL || p_st_conn== NULL
       || p_st_packet->p_payload == NULL
       || p_st_packet->ui_payload_len == 0)
    {
        return APM_L7_IS_NO;
    }

    ui_len = p_st_packet->ui_payload_len;         /* packet数据长度 */
    p_data = p_st_packet->p_payload;              /* packet数据内容 */
    if (ui_len < CUPS_LEN_LEN + CUPS_TPDU_LEN + CUPS_MSG_TP_LEN + CUPS_MAP_MAX_LEN)
    {
        goto error;
    }

    /* 创建bytebuff */
    p_st_data = bytebuff_creat();
    if (p_st_data == NULL)
    {
        goto error;
    }
    i_ret = bytebuff_add(p_st_data, p_data, ui_len);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    /* 取得packet长度 */
    i_ret = cups_get_len(p_st_data, CUPS_LEN_LEN, &ui_packet_len);
    if (i_ret != FR_SUCC || ui_packet_len + CUPS_LEN_LEN != ui_len
        || ui_packet_len > 1892 + CUPS_LEN_LEN)
    {
        goto error;
    }
    /* 取得TPDU长度 */
    bytebuff_get_char(p_st_data, &u8_tpdu_len);
    if (i_ret != FR_SUCC || u8_tpdu_len != CUPS_TPDU_LEN)
    {
        goto error;
    }

    /* 跳过TPDU */
    bytebuff_skip(p_st_data, CUPS_TPDU_LEN - 1);
    /* 取得message type */
    i_ret = cups_get_len(p_st_data, CUPS_MSG_TP_LEN, &ui_msg_type);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }
    bytebuff_free(&p_st_data);

    /* 根据message type设定方向 */
    switch (ui_msg_type)
    {
        case CUPS_0100_REQ:
        case CUPS_0200_REQ:
        case CUPS_0220_REQ:
        case CUPS_0320_REQ:
        case CUPS_0400_REQ:
        case CUPS_0620_REQ:
        case CUPS_0800_REQ:
        case CUPS_0820_REQ:
            if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
            {
                i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip
                                         , p_st_packet->dst_port);
            }
            break;

        case CUPS_0110_RESP:
        case CUPS_0210_RESP:
        case CUPS_0230_RESP:
        case CUPS_0330_RESP:
        case CUPS_0410_RESP:
        case CUPS_0630_RESP:
        case CUPS_0810_RESP:
        case CUPS_0830_RESP:
            if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
            {
                i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip
                                        , p_st_packet->src_port);
            }
            break;

        default:
            i_ret = FR_FAIL;
            break;
    }
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    frservice_add(g_p_apm_context, MODULE_L7PROTO
                  , p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
    return APM_L7_IS_YES;

error:
    bytebuff_free(&p_st_data);
    if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip
                             , p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
            return APM_L7_IS_YES;
        }
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip
                             , p_st_packet->src_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
            return APM_L7_IS_YES;
        }
    }
    else
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip
                             , p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;
    }
    return APM_L7_IS_NO;
}

/*******************************************************************************
*  FUNC     :  CUPS的packet解析
*  ARGS     :  p_st_conn(入力链接信息)
            :  p_st_packet(入力packet信息)
            :  p_st_hash_report(保存Frreport_data)
*  RTN      :  参照module.h
*  NOTE     :
*******************************************************************************/
int cups_analysis(Conntrack *p_st_conn
                  , Apm_packet *p_st_packet
                  , Frhash_header *p_st_hash_report)
{
    int i_ret = FR_SUCC;
    L7_session *p_st_session = NULL;              /* L7session */
    L7session_cups_private *p_st_private = NULL;   /* cups的私有数据 */

    if(p_st_conn == NULL || p_st_packet == NULL
        || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /*
    * 如果入力p_st_packet是FIN包, 说明本次cups的connection结束,
    * 释放本次session信息. 如果入力p_st_packet是SYN包,
    * 说明新的cups的connection开始了, 释放上次可能残留的session信息
    */
//    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN
//        || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
//    {
//        /* 销毁所有相关本次cups的connection的数据 */
//        cups_session_destroy((void *)(p_st_session->p_session_private));
//        p_st_session->p_session_private = NULL;
//        return APM_L7_ANALYZE_SUCC;
//    }

    /* 本次链路的第一个有效packet包,创建链路 */
    if (p_st_session->p_session_private == NULL)
    {
        /* 初始化cups的私有数据 */
        i_ret = __cups_init_private(p_st_session);
        if (i_ret != FR_SUCC)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        /* 设置session ID */
        fruuid(p_st_session->arr_session_id);
    }

    p_st_private = (L7session_cups_private *)p_st_session->p_session_private;
    /* 设置解析数据 */
    i_ret = __cups_set_analysis_data(p_st_conn, p_st_packet, p_st_private);
    if (i_ret == APM_L7_ANALYZE_TODO)
    {
        frdbg("need more data\n");
        return APM_L7_ANALYZE_TODO;
    }
    else if (i_ret == APM_L7_ANALYZE_FAIL)
    {
        frdbg("call __cups_set_analysis_data failed\n");
        __cups_destroy_curr_info(p_st_private);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 解析packet */
    switch (p_st_private->p_st_fragment->i_req_resp)
    {
        case FR_CLIENT_IP_PORT: /* 解析request */
            i_ret = cups_parse_request(p_st_conn, p_st_private, p_st_hash_report);
            if (i_ret == APM_L7_ANALYZE_FAIL)
            {
                frdbg("Parse request failed\n");
                __cups_destroy_curr_info(p_st_private);
                return APM_L7_ANALYZE_FAIL;
            }
            cups_init_fragment(p_st_private->p_st_fragment);
            break;

        case FR_SRV_IP_PORT: /* 解析response */
            i_ret = cups_parse_response(p_st_conn, p_st_private, p_st_hash_report);
            __cups_destroy_curr_info(p_st_private);
            if (i_ret == APM_L7_ANALYZE_FAIL)
            {
                frdbg("Parse response failed\n");
                return APM_L7_ANALYZE_FAIL;
            }
            break;

        default: /* 类型未知 */
            i_ret = APM_L7_ANALYZE_FAIL;
            break;
    }

    /* 返回 */
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  私有信息销毁
*  ARGS     :  p_private_session(cups的私有session数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
int cups_session_destroy(void *p_private_session)
{
    L7session_cups_private *p_st_private = (L7session_cups_private *)p_private_session;

    /* 判断session是否为空 */
    if (p_st_private == NULL)
    {
        return FR_SUCC;
    }

    /* 销毁request数据 */
    if (p_st_private->p_st_req)
    {
        cups_destroy_request(&(p_st_private->p_st_req));
    }

    /* 销毁response数据 */
    if (p_st_private->p_st_resp)
    {
        cups_destroy_response(&p_st_private->p_st_resp);
    }

    /* 销毁分片数据 */
    if (p_st_private->p_st_fragment)
    {
        cups_destroy_fragment(&p_st_private->p_st_fragment);
    }

    frfree(p_st_private);

    return FR_SUCC;
}
